/*
 * edge.cpp
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#include "../../../../../../include/base/cell_models/ACM/geometry/base/edge.h"
#include "../../../../../../include/base/cell_models/ACM/ActiveCableModel.h"
#include <cstdlib>
#include "../../../../../../include/base/cell_models/ACM/helper/helper.h"

using namespace std;

Edge::Edge(Vertex* HEAD, Vertex* TAIL) {
	head = HEAD;
	tail = TAIL;

	head->getEdgesConnectingVertex()->push_back(this);
	tail->getEdgesConnectingVertex()->push_back(this);
}

bool Edge::operator==(Edge& e) const {
	if (head == e.getHead() && tail == e.getTail())
		return true;
	else if (head == e.getTail() && tail == e.getHead())
		return true;
	else
		return false;
}

bool Edge::intersects(Edge & e){
	Vertex P1 = *tail;
	Vertex P2 = *head;
	Vertex P3 = *e.getTail();
	Vertex P4 = *e.getHead();
	Vertex t1 = P2 - P1;
	Vertex t2 = P4 - P3;
	Vertex diff = P3 - P1;


	vector<double> A;
	A.push_back(t1.getX());
	A.push_back(t2.getX()*(-1));
	A.push_back(t1.getY());
	A.push_back(t2.getY()*(-1));

	Helper::invert2x2Matrix(A);
	double alpha = diff.getX() * A[0] + diff.getY() * A[1];
	double beta = diff.getX() * A[2] + diff.getY() * A[3];
	return ((alpha>=0) && (beta>=0) && (alpha<=1) && (beta<=1));
}

const bool Edge::connectsVertices(Vertex* V1, Vertex* V2) const {
	if (V1 == head && V2 == tail)
		return true;
	else if (V1 == tail && V2 == head)
		return true;
	else
		return false;
}

const bool Edge::connectsVerticesInOrder(Vertex* TAIL, Vertex* HEAD) const {
	if (HEAD == head && TAIL == tail)
		return true;
	else
		return false;
}

const bool Edge::containsVertex(Vertex* v) const {
	if (v == head || v == tail)
		return true;
	else
		return false;
}

Vertex* Edge::getSecondTip(Vertex * firstTip){
	if(firstTip == head) return tail;
	else if(firstTip == tail) return head;
	else return NULL;
}

Triangle * Edge::getSecondAdjacentTriangle(Triangle * fristAdjacentTriangle){
	if(adjacentTriangles.size() != 2) return NULL; //Only one adjacent triangle or error
	if(fristAdjacentTriangle == adjacentTriangles[0]) return adjacentTriangles[1];
	else if(fristAdjacentTriangle == adjacentTriangles[1]) return adjacentTriangles[0];
	else return NULL; //Triangle is not adjacent to this edge
}

bool Edge::isEndlineOfSF(){
	int sf_nr = getValueOfAttribute(ActiveCableModel::FIELD_FIBRENUMBER);
	if(sf_nr == 0) return false;
	bool continuesInHeadDirection, continuesInTailDirection;
	continuesInHeadDirection = !head->isEndpointOfSF(sf_nr);
	continuesInTailDirection = !tail->isEndpointOfSF(sf_nr);
	if(continuesInHeadDirection && continuesInTailDirection) return false;
	else return true;
}

Vertex * Edge::getEndpointOfFiber(){
	if(!isEndlineOfSF()){
		cout << "This edge is not an end point of a stress fiber." << endl;
		exit(0);
	}
	int sf_nr = getValueOfAttribute(ActiveCableModel::FIELD_FIBRENUMBER);
	if(head->isEndpointOfSF(sf_nr)) return head;
	else return tail;
}
